#pragma once
#include <iostream>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

const int defaultcap = 5;

template<class T>
class RingQueue
{
public:
    RingQueue(int cap = defaultcap)
        :_cap(cap)
        , _q(cap)
        , _blank_sem(cap)
        , _p_sep(0)
        , _data_sem(0)
        , _c_sep(0)
    {

    }

    //生产者调用
    void Push(const T& data)
    {
        _blank_sem.P(); //信号量 -- 预定机制，所以先申请信号量，再加锁
        _p_mutex.lock();
        _q[_p_sep++] = data;
        _p_sep %= _cap;
        _data_sem.V();
        _p_mutex.unlock();
    }

    //消费者调用
    void Pop(T* out)
    {
        _data_sem.P(); //信号量 -- 预定机制，所以先申请信号量，再加锁
        _c_mutex.lock();
        *out = _q[_c_sep];
        _c_sep++;
        _c_sep %= _cap;
        _blank_sem.V();
        _c_mutex.unlock();
    }
private:
    std::vector<T> _q; 
    int _cap;

    //生产者
    Sem _blank_sem; //空位置的个数
    int _p_sep; //生产的位置

    //消费者
    Sem _data_sem; //数据的个数
    int _c_sep; //消费的位置

    //两个互斥锁 -- 分别确保生产者和消费者各自的互斥关系
    Mutex _p_mutex;
    Mutex _c_mutex;
};